﻿using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.Linq.Extensions;
using Microsoft.EntityFrameworkCore;
using pandx.Mulan.Authorization;
using pandx.Mulan.Authorization.Users;
using pandx.Mulan.Dto;
using pandx.Mulan.Form.FormSchemes.Dto;
using pandx.Mulan.Form.FormSchemes.Exporting;
using pandx.Mulan.Forms;

namespace pandx.Mulan.Form.FormSchemes
{
    public class FormSchemeAppService:MulanAppServiceBase,IFormSchemeAppService
    {
        private readonly IRepository<FormScheme, long> _formSchemeRepository;
        private readonly IRepository<User, long> _userRepository;
        private readonly IFormSchemeListExcelExporter _formSchemeListExcelExporter;

        public FormSchemeAppService(
            IRepository<FormScheme, long> formSchemeRepository,
            IRepository<User,long> userRepository,
            IFormSchemeListExcelExporter formSchemeListExcelExporter
            )
        {
            _userRepository = userRepository;
            _formSchemeRepository = formSchemeRepository;
            _formSchemeListExcelExporter = formSchemeListExcelExporter;
        }

        [AbpAuthorize(AppPermissions.Pages_Administration_FormSchemes_Browse)]
        public async Task<PagedResultDto<FormSchemeListDto>> ObtainFormSchemes(ObtainFormSchemesInput input)
        {

            var query = CreateFormSchemeAndUsersQuery(input);

            var formSchemesCount = await query.CountAsync();
            var formSchemes = await query.OrderBy(input.Sorting).PageBy(input).ToListAsync();
            var dtos = formSchemes.Select(item =>
            {
                var dto = ObjectMapper.Map<FormSchemeListDto>(item.FormScheme);
                dto.CreatorUserName = item.User.UserName;
                dto.CreatorName = item.User.Name;
                return dto;
            }).ToList();
            return new PagedResultDto<FormSchemeListDto>(formSchemesCount, dtos);
        }
        
        public async Task CreateOrUpdateFormScheme(CreateOrUpdateFormSchemeInput input)
        {
            if (input.FormScheme.Id.HasValue)
            {
                await UpdateFormSchemeAsync(input);
            }
            else
            {
                await CreateFormSchemeAsync(input);
            }
        }

        [AbpAuthorize(AppPermissions.Pages_Administration_FormSchemes_Update)]
        protected virtual async Task UpdateFormSchemeAsync(CreateOrUpdateFormSchemeInput input)
        {
            var formScheme = await _formSchemeRepository.GetAsync(input.FormScheme.Id.Value);
            ObjectMapper.Map(input.FormScheme, formScheme);
            await CurrentUnitOfWork.SaveChangesAsync();
        }

        [AbpAuthorize(AppPermissions.Pages_Administration_FormSchemes_Create)]
        protected virtual async Task CreateFormSchemeAsync(CreateOrUpdateFormSchemeInput input)
        {
            if (AbpSession.TenantId.HasValue)
            {
            }
            var formScheme = ObjectMapper.Map<FormScheme>(input.FormScheme);

            formScheme.TenantId=AbpSession.TenantId;

            await _formSchemeRepository.InsertAsync(formScheme);
            await CurrentUnitOfWork.SaveChangesAsync();
        }

        [AbpAuthorize(AppPermissions.Pages_Administration_FormSchemes_Create,AppPermissions.Pages_Administration_FormSchemes_Update)]
        public async Task<GetFormSchemeForEditOutput> GetFormSchemeForEdit(NullableIdDto<long> input)
        {
            var output = new GetFormSchemeForEditOutput();
            if (input.Id.HasValue)
            {
                var formScheme = await _formSchemeRepository.GetAsync(input.Id.Value);
                output.FormScheme = ObjectMapper.Map<FormSchemeEditDto>(formScheme);
            }
            else
            {
                var formScheme = new FormSchemeEditDto();
                output.FormScheme = formScheme;
            }

            return output;
        }

        [AbpAuthorize(AppPermissions.Pages_Administration_FormSchemes_Browse)]
        public async Task<FormSchemeListDto> GetFormScheme(EntityDto<long> input)
        {
            var formScheme = await _formSchemeRepository.GetAsync(input.Id);
            return ObjectMapper.Map<FormSchemeListDto>(formScheme);
        }

        [AbpAuthorize(AppPermissions.Pages_Administration_FormSchemes_Delete)]
        public async Task DeleteFormScheme(EntityDto<long> input)
        {
            var formScheme = await _formSchemeRepository.GetAsync(input.Id);
            await _formSchemeRepository.DeleteAsync(input.Id);
        }

        [AbpAuthorize(AppPermissions.Pages_Administration_FormSchemes_Export)]
        public async Task<FileDto> ObtainFormSchemesToExcel(ObtainFormSchemesInput input)
        {
            var formSchemes = await CreateFormSchemeAndUsersQuery(input).AsNoTracking().OrderBy(input.Sorting).ToListAsync();
            var dtos=formSchemes.Select(item =>
            {
                var dto = ObjectMapper.Map<FormSchemeListDto>(item.FormScheme);
                dto.CreatorUserName = item.User.UserName;
                dto.CreatorName = item.User.Name;
                return dto;
            }).ToList();
            return _formSchemeListExcelExporter.ExportToExcel(dtos);
        }

        private IQueryable<FormSchemeAndUser> CreateFormSchemeAndUsersQuery(ObtainFormSchemesInput input)
        {
            if (input.FormType == null || input.FormType?.Count == 0)
            {
                input.FormType = new List<int> { 0,1};
            }

            var query = from formScheme in _formSchemeRepository.GetAll()
                join user in _userRepository.GetAll() on formScheme.CreatorUserId equals user.Id into userJoin
                from joinedUser in userJoin.DefaultIfEmpty()
                where formScheme.CreationTime >= input.StartTime && formScheme.CreationTime <= input.EndTime
                select new FormSchemeAndUser
                {
                    FormScheme = formScheme,
                    User=joinedUser
                };
            query = query
                .Where(x=>input.FormType.Contains(x.FormScheme.FormType))
                .WhereIf(!input.Filter.IsNullOrWhiteSpace(), x => x.FormScheme.SchemeName.Contains(input.Filter) ||x.FormScheme.Description.Contains(input.Filter));
            return query;
        }
        
        [AbpAuthorize(AppPermissions.Pages_Administration_FormSchemes_Create,AppPermissions.Pages_Administration_FormSchemes_Update)]
        public async Task<ValidateOutput> ValidateFormSchemeName(ValidateInput<string, int> input)
        {
            if (input.Id == 0)
            {
                var one = await _formSchemeRepository.GetAll().SingleOrDefaultAsync(r => r.SchemeName == input.Value);
                if (one != null)
                {
                    return new ValidateOutput
                    {
                        Status = false,
                        Message = "表单模板名 " + input.Value + " 已被占用"
                    };
                }
                else
                {
                    return new ValidateOutput
                    {
                        Status = true,
                    };
                }
            }
            else
            {
                var one = await _formSchemeRepository.GetAll().SingleOrDefaultAsync(r =>
                    r.SchemeName == input.Value && r.Id != input.Id);
                if (one != null)
                {
                    return new ValidateOutput
                    {
                        Status = false,
                        Message = "表单模板名 " + input.Value + " 已被占用"
                    };
                }
                else
                {
                    return new ValidateOutput
                    {
                        Status = true,
                    };
                }
            }
        }
    }
}
